Package org.python.pydev.django_templates.completions

Source Code of org.python.pydev.django_templates.completions.DjContentAssistProcessor

/**
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
package org.python.pydev.django_templates.completions;

import java.util.ArrayList;

import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
import org.eclipse.jface.text.templates.Template;
import org.python.pydev.django_templates.completions.templates.DjContextType;
import org.python.pydev.django_templates.completions.templates.DjTemplateCompletionProcessor;
import org.python.pydev.django_templates.editor.DjSourceConfiguration;
import org.python.pydev.plugin.PydevPlugin;
import org.python.pydev.ui.UIConstants;

import com.aptana.editor.common.contentassist.ICommonContentAssistProcessor;
import com.aptana.editor.css.CSSSourceConfiguration;
import com.aptana.editor.css.contentassist.CSSContentAssistProcessor;
import com.aptana.editor.html.HTMLSourceConfiguration;

public class DjContentAssistProcessor implements IContentAssistProcessor, ICommonContentAssistProcessor {

    private IContentAssistProcessor htmlContentAssistProcessor;
    private DjTemplateCompletionProcessor templatesContentAssistProcessor;
    private DjTemplateCompletionProcessor templatesTagsContentAssistProcessor;
    private DjTemplateCompletionProcessor templatesFiltersContentAssistProcessor;
    private String contentType;
    private final boolean isDefaultContentType;

    public DjContentAssistProcessor(String contentType, IContentAssistProcessor htmlContentAssistProcessor) {
        this.contentType = contentType;
        this.isDefaultContentType = this.contentType.equals(IDocument.DEFAULT_CONTENT_TYPE);
        this.htmlContentAssistProcessor = htmlContentAssistProcessor;
    }

    private DjTemplateCompletionProcessor getTemplatesContentAssistProcessor() {
        if (this.templatesContentAssistProcessor == null) {
            this.templatesContentAssistProcessor = new DjTemplateCompletionProcessor(
                    DjContextType.DJ_COMPLETIONS_CONTEXT_TYPE, PydevPlugin.getImageCache().get(
                            UIConstants.COMPLETION_TEMPLATE), false);
        }
        return this.templatesContentAssistProcessor;
    }

    private DjTemplateCompletionProcessor getTemplatesTagsContentAssistProcessor() {
        if (this.templatesTagsContentAssistProcessor == null) {
            this.templatesTagsContentAssistProcessor = new DjTemplateCompletionProcessor(
                    DjContextType.DJ_TAGS_COMPLETIONS_CONTEXT_TYPE, null, true);
        }
        return this.templatesTagsContentAssistProcessor;
    }

    private DjTemplateCompletionProcessor getTemplatesFiltersContentAssistProcessor() {
        if (this.templatesFiltersContentAssistProcessor == null) {
            this.templatesFiltersContentAssistProcessor = new DjTemplateCompletionProcessor(
                    DjContextType.DJ_FILTERS_COMPLETIONS_CONTEXT_TYPE, null, true);
        }
        return this.templatesFiltersContentAssistProcessor;
    }

    public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) {
        ICompletionProposal[] proposals = null;
        if (this.htmlContentAssistProcessor != null) {
            proposals = this.htmlContentAssistProcessor.computeCompletionProposals(viewer, offset);
        }

        return addDjProposals(viewer, offset, proposals);
    }

    /**
     * Heuristically extracts the prefix used for determining template relevance
     * from the viewer's document. The default implementation returns the String from
     * offset backwards that forms a java identifier.
     *
     * @param viewer the viewer
     * @param offset offset into document
     * @return the prefix to consider
     * @see #getRelevance(Template, String)
     */
    public String extractPrefix(ITextViewer viewer, int offset) {
        IDocument document = viewer.getDocument();
        return extractPrefix(document, offset);
    }

    public String extractPrefix(IDocument document, int offset) {
        int i = offset;
        if (i > document.getLength())
            return ""; //$NON-NLS-1$

        try {
            while (i > 0) {
                char ch = document.getChar(i - 1);
                if (!Character.isJavaIdentifierPart(ch) && ch != '|') {
                    break;
                }
                i--;
                if (ch == '|') {
                    break; //We also want to add the | to the prefix.
                }
            }

            return document.get(i, offset - i);
        } catch (BadLocationException e) {
            return ""; //$NON-NLS-1$
        }
    }

    private ICompletionProposal[] addDjProposals(ITextViewer viewer, int offset, ICompletionProposal[] proposals) {

        boolean completionsForTags = showCompletionsInsideDjangoContext(viewer.getDocument(), offset);

        ICompletionProposal[] djProposals;
        DjTemplateCompletionProcessor processor;
        String str = extractPrefix(viewer, offset);

        if (completionsForTags) {
            if (str.startsWith("|")) {
                processor = this.getTemplatesFiltersContentAssistProcessor();
                str = str.substring(1);
            } else {
                processor = this.getTemplatesTagsContentAssistProcessor();
            }
        } else {
            processor = this.getTemplatesContentAssistProcessor();
        }

        djProposals = processor.computeCompletionProposals(viewer, offset);

        ArrayList<ICompletionProposal> djProposalsList = new ArrayList<ICompletionProposal>();
        for (int j = 0; j < djProposals.length; j++) {
            if (djProposals[j].getDisplayString().startsWith(str)) {
                ICompletionProposal p = djProposals[j];
                djProposalsList.add(p);
            }
        }

        if (proposals != null && proposals.length > 0) {
            for (int i = 0; i < proposals.length; i++) {
                if (proposals[i].getDisplayString().startsWith(str)) {
                    ICompletionProposal p = proposals[i];
                    djProposalsList.add(p);
                }
            }
        }
        return djProposalsList.toArray(new ICompletionProposal[djProposalsList.size()]);
    }

    public boolean showCompletionsInsideDjangoContext(IDocument document, int offset) {
        //Content type we're at:
        //Request on __html__dftl_partition_content_type: templates in the html level
        //Request on __dftl_partition_content_type:  |{%| euo a=|"test"| nthnh  |%|}|
        //Request on __djhtml__dftl_partition_content_type: at {% |roto| %}

        //So, we use a simple heuristic to know what we should use:
        //1. if it's at __djhtml__dftl_partition_content_type, we know exactly where we are (inside a django tag)
        //2. If we're at __html__dftl_partition_content_type, we also know we should only get completions that are top-level
        //3. __dftl_partition_content_type is the 'gray' area, so, we go backwards to discover where we are (looking for
        //the first occurrence of __djhtml__dftl_partition_content_type or __html__dftl_partition_content_type or the
        //sequence {% (starting, meaning inside django tag) or %} (ending, meaning outside django tag.)

        boolean completionsForTags = true;
        if (DjSourceConfiguration.DEFAULT.equals(this.contentType)) {
            completionsForTags = true;

        } else if (HTMLSourceConfiguration.DEFAULT.equals(this.contentType)
                || CSSSourceConfiguration.DEFAULT.equals(this.contentType)) {
            completionsForTags = false;

        } else if (IDocument.DEFAULT_CONTENT_TYPE.equals(this.contentType)) {
            try {
                int discoverOffset = offset;
                while (discoverOffset >= 0) {
                    String cont = document.getContentType(discoverOffset);
                    discoverOffset--;
                    if (DjSourceConfiguration.DEFAULT.equals(cont)) {
                        completionsForTags = true;
                        break;

                    } else if (HTMLSourceConfiguration.DEFAULT.equals(cont)
                            || CSSSourceConfiguration.DEFAULT.equals(cont)) {
                        completionsForTags = false;
                        break;
                    }
                }

            } catch (BadLocationException e) {
                completionsForTags = true; //we got to the end and didn't find the scope, so, just go on and show the 'simple' ones.
            }
        }
        return completionsForTags;
    }

    public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) {
        return null;
    }

    public char[] getCompletionProposalAutoActivationCharacters() {
        if (htmlContentAssistProcessor != null) {
            return htmlContentAssistProcessor.getCompletionProposalAutoActivationCharacters();
        }
        return null;
    }

    public char[] getContextInformationAutoActivationCharacters() {
        return null;
    }

    public String getErrorMessage() {
        return null;
    }

    public IContextInformationValidator getContextInformationValidator() {
        return null;
    }

    public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset, char activationChar,
            boolean autoActivated) {
        ICompletionProposal[] proposals = null;
        boolean completeDj = true;
        if (isDefaultContentType) {
            try {
                int tempOffset = offset;
                while (tempOffset >= 0) {
                    tempOffset--;
                    char prevChar = viewer.getDocument().getChar(tempOffset);
                    if (prevChar == '<') {
                        completeDj = false;
                        break;
                    }
                    if (!Character.isJavaIdentifierPart(prevChar)) {
                        break;
                    }
                }
            } catch (BadLocationException e) {
            }
        }
        if (this.htmlContentAssistProcessor instanceof ICommonContentAssistProcessor) {
            ICommonContentAssistProcessor commonContentAssistProcessor = (ICommonContentAssistProcessor) this.htmlContentAssistProcessor;
            proposals = commonContentAssistProcessor.computeCompletionProposals(viewer, offset, activationChar,
                    autoActivated);
        } else if (this.htmlContentAssistProcessor != null) {
            proposals = this.htmlContentAssistProcessor.computeCompletionProposals(viewer, offset);
        }

        //css and django templates 'compete' in the same namespace, so, we have to add an exception in the check below...
        if (!(this.htmlContentAssistProcessor instanceof CSSContentAssistProcessor) && proposals != null
                && proposals.length > 0) {
            completeDj = false;
        }

        if (completeDj) {
            return addDjProposals(viewer, offset, proposals);
        }
        return proposals;
    }

    /* (non-Javadoc)
     * @see com.aptana.editor.common.contentassist.ICommonContentAssistProcessor#isValidAutoActivationLocation(char, int, org.eclipse.jface.text.IDocument, int)
     */
    public boolean isValidAutoActivationLocation(char c, int keyCode, IDocument document, int offset) {
        if (htmlContentAssistProcessor instanceof ICommonContentAssistProcessor) {
            return ((ICommonContentAssistProcessor) htmlContentAssistProcessor).isValidAutoActivationLocation(c,
                    keyCode, document, offset);
        }
        return false;
    }

    /* (non-Javadoc)
     * @see com.aptana.editor.common.contentassist.ICommonContentAssistProcessor#isValidIdentifier(char, int)
     */
    public boolean isValidIdentifier(char c, int keyCode) {
        if (htmlContentAssistProcessor instanceof ICommonContentAssistProcessor) {
            return ((ICommonContentAssistProcessor) htmlContentAssistProcessor).isValidIdentifier(c, keyCode);
        }
        return false;
    }

    /* (non-Javadoc)
     * @see com.aptana.editor.common.contentassist.ICommonContentAssistProcessor#isValidActivationCharacter(char, int)
     */
    public boolean isValidActivationCharacter(char c, int keyCode) {
        if (htmlContentAssistProcessor instanceof ICommonContentAssistProcessor) {
            return ((ICommonContentAssistProcessor) htmlContentAssistProcessor).isValidActivationCharacter(c, keyCode);
        }
        return false;
    }

    /*
     * (non-Javadoc)
     * @see com.aptana.editor.common.contentassist.ICommonContentAssistProcessor#dispose()
     */
    public void dispose() {
    }

    /*
     * (non-Javadoc)
     * @see com.aptana.editor.common.contentassist.ICommonContentAssistProcessor#getActiveUserAgentIds()
     */
    public String[] getActiveUserAgentIds() {
        return new String[0];
    }

}
TOP

Related Classes of org.python.pydev.django_templates.completions.DjContentAssistProcessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.